using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using EnvDTE;

namespace VSSDKAssist.Assets.Helpers
{
	/// <summary>
	/// Iterator for Visual Studio CodeElements
	/// </summary>
	[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
	public class CodeElementsIterator : IEnumerable<CodeElement>
	{
		#region Fields
		private CodeElements elements; 
		#endregion

		#region Constructors
		/// <summary>
		/// Initializes a new instance of the <see cref="CodeElementsIterator"/> class.
		/// </summary>
		/// <param name="projectItem">The project item.</param>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
		public CodeElementsIterator(ProjectItem projectItem)
		{
			Guard.ArgumentNotNull(projectItem, "projectItem");

			if(projectItem.FileCodeModel != null)
			{
				elements = projectItem.FileCodeModel.CodeElements;
			}
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="CodeElementsIterator"/> class.
		/// </summary>
		/// <param name="codeElement">The code element.</param>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
		public CodeElementsIterator(CodeElement codeElement)
		{
			Guard.ArgumentNotNull(codeElement, "codeElement");

			elements = codeElement.Children;
		} 
		#endregion

		#region IEnumerable<CodeElement> Members

		/// <summary>
		/// Returns an enumerator that iterates through the collection.
		/// </summary>
		/// <returns>
		/// A <see cref="T:System.Collections.Generic.IEnumerator`1"></see> that can be used to iterate through the collection.
		/// </returns>
		public IEnumerator<CodeElement> GetEnumerator()
		{
			if(elements == null)
			{
				yield break;
			}
			foreach(CodeElement element in EnumerateCodeElements(elements))
			{
				yield return element;
			}
		}
		#endregion

		#region Private Implementation
		private IEnumerable<CodeElement> EnumerateCodeElements(CodeElements codeElements)
		{
			foreach(CodeElement element in codeElements)
			{
				yield return element;
				foreach(CodeElement subElement in EnumerateCodeElements(element.Children))
				{
					yield return subElement;
				}
			}
		} 
		#endregion

		#region IEnumerable Members

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		#endregion
	}
}